# coding = utf-8
from django.db import transaction
from django.db.models import F
from rest_framework import serializers, status, exceptions
from rest_framework.serializers import ModelSerializer

from polls.models import Question, Choice, VoteDetail, ChoiceImage
from wxchat.api.utils import get_user_by_openid, get_openid_from_header


class ChoiceImageSerializer(ModelSerializer):
    """
    选项图片
    """
    class Meta:
        model = ChoiceImage
        exclude = ["update_time", "add_time"]


class ChoiceSerializer(ModelSerializer):
    """
    分类
    """
    id = serializers.IntegerField(required=False)
    images = ChoiceImageSerializer(many=True, read_only=True)

    class Meta:
        model = Choice
        exclude = ["update_time", "add_time"]


class QuestionSerializer(ModelSerializer):
    """
    投票管理
    """
    question_name = serializers.CharField(source="question.name", read_only=True)
    flag_name = serializers.CharField(source="get_flag_display", read_only=True)
    cate_name = serializers.CharField(source="get_category_display", read_only=True)
    choices = ChoiceSerializer(many=True, required=False)

    class Meta:
        model = Question
        exclude = ["update_time", "add_time"]

    def create(self, validated_data):
        choices = validated_data.pop('choices', [])
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            instance = None
            try:
                instance = self.Meta.model.objects.create(**validated_data)

                create_list = [Choice(question=instance, **c) for c in choices]

                Choice.objects.bulk_create(create_list)

            except Exception as e:
                print("excetpion: ", e)
                transaction.savepoint_rollback(save_id)
                msg = {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'message': '保存失败'
                }
                print(msg)
                raise exceptions.ValidationError(msg)

            transaction.savepoint_commit(save_id)
        return instance

    def update(self, instance, validated_data):
        choices = validated_data.pop('choices', [])
        with transaction.atomic():
            # 创建事务保存点
            save_id = transaction.savepoint()
            try:
                instance.name = validated_data.get('name', instance.name)
                instance.desc = validated_data.get('desc', instance.desc)
                instance.max_num = validated_data.get('max_num', instance.max_num)
                instance.begin_date = validated_data.get('begin_date', instance.begin_date)
                instance.end_date = validated_data.get('end_date', instance.end_date)
                instance.save()

                for c in choices:
                    _id = c.pop("id", None)
                    if _id:
                        Choice.objects.filter(id=_id).update(**c)
                    else:
                        Choice.objects.create(question=instance, **c)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)
                msg = {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'message': '修改失败'
                }
                print(msg)
                raise exceptions.ValidationError(msg)

            transaction.savepoint_commit(save_id)

        return instance


class VoteDetailSerializer(ModelSerializer):
    """
    投票详情
    """
    question_name = serializers.CharField(source="question.name", read_only=True)

    class Meta:
        model = VoteDetail
        exclude = ["add_time"]


class WxQuestionSerializer(ModelSerializer):
    """
    投票管理
    """
    question_name = serializers.CharField(source="question.name", read_only=True)
    choices = ChoiceSerializer(many=True, required=False)

    class Meta:
        model = Question
        exclude = ["update_time", "add_time"]

    def update(self, instance, validated_data):
        choices = validated_data.pop('choices', [])
        request = self.context["request"]
        openid = request.data.get("openid")
        exists = VoteDetail.objects.filter(openid=openid, question_id=instance.id).exists()
        if exists:
            msg = {
                'status_code': status.HTTP_400_BAD_REQUEST,
                'message': '您已经投过票,不能再投!'
            }
            raise exceptions.ValidationError(msg)

        with transaction.atomic():
            save_id = transaction.savepoint()
            try:
                for c in choices:
                    _id = c.pop("id", None)
                    Choice.objects.filter(id=_id).update(vote_nums=F("vote_nums") + 1)
                # 保存投票数据
                user = get_user_by_openid(openid)
                if not openid or not user:
                    msg = {
                        'status_code': status.HTTP_400_BAD_REQUEST,
                        'message': '用户无效'
                    }
                    raise exceptions.ValidationError(msg)
                choice_list = [item["name"] for item in choices]
                save_data = {
                    "openid": openid,
                    "nickname": user.nickname,
                    "question": instance,
                    "choice_name": ",".join(choice_list)
                }
                VoteDetail.objects.create(**save_data)
            except Exception as e:
                print(e)
                transaction.savepoint_rollback(save_id)
                msg = {
                    'status_code': status.HTTP_400_BAD_REQUEST,
                    'message': '投票失败'
                }
                print(msg)
                raise exceptions.ValidationError(msg)

            transaction.savepoint_commit(save_id)

        return instance
